'
'   XC Engine. A simple engine to drive the Internet Explorer web browser
'   Copyright (C) 2009 Stanislav Hordiyenko
'
'   This program is free software; you can redistribute it and/or modify
'   it under the terms of the GNU General Public License as published by
'   the Free Software Foundation; either version 3 of the License, or
'   (at your option) any later version.
'
'   This program is distributed in the hope that it will be useful,
'   but WITHOUT ANY WARRANTY; without even the implied warranty of
'   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
'   GNU General Public License for more details.
'
'   You should have received a copy of the GNU General Public License
'   along with this program; if not, see http://www.gnu.org/licenses
'   or write to the Free Software Foundation,Inc., 51 Franklin Street,
'   Fifth Floor, Boston, MA 02110-1301 USA
'

Class ElementsCollection
	Private arrElementsCollection
	
	Public Sub Class_Initialize()
		ReDim arrElementsCollection(-1)
	End Sub
	
	Public Sub Class_Terminate()
		ReDim arrElementsCollection(-1)
	End Sub
	
	Public Sub AddElement(ByVal objHtmlElement)
		ReDim Preserve arrElementsCollection(UBound(arrElementsCollection)+1)
		
		Set arrElementsCollection(UBound(arrElementsCollection)) = objHtmlElement
	End Sub
	
	Public Default Function Item(ByVal intIndex)
		Set Item = arrElementsCollection(intIndex-1)
	End Function
	
	Public Function Count()
		Count = UBound(arrElementsCollection)+1
	End Function
End Class

Private Function Internal_FilterElements(ByVal objHtmlElement, ByVal strHtmlProperties, ByRef colElementsCollection) 'Method return boolean value
	arrHtmlProperties = Split(strHtmlProperties, ", ")
	
	Set objProperties = WScript.CreateObject("Scripting.Dictionary")

	For i=0 To UBound(arrHtmlProperties)
		arrProperty = Split(arrHtmlProperties(i), ": ")
		
		objProperties.Add Trim(arrProperty(0)), Trim(arrProperty(1))
	Next
	
	If objProperties.Exists("element class") Then
		strElementClass = LCase(objProperties.Item("element class"))
		
		objProperties.Remove "element class"
	End If
	
	Select Case strElementClass
		Case "text field"
			objProperties.Add "type", "text|password"
			
		Case "radio button"
			objProperties.Add "type", "radio"
			
		Case "file field"
			objProperties.Add "type", "file"
			
		Case "check box"
			objProperties.Add "type", "checkbox"
			
		Case "button"
			objProperties.Add "type", "submit|button|image|reset"
	
	End Select
	
	If objProperties.Exists("index") Then
		intPropertyIndex = CInt(objProperties.Item("index"))
		
		objProperties.Remove "index"
	Else
		intPropertyIndex = 0
	End If
	
	arrPropertyNames = objProperties.Keys
	
	If strElementClass <> "frame" Then
		Set objElementsCollection = objHtmlElement.GetElementsByTagName(ElementClassToHtmlTag(strElementClass))
	Else
		If UCase(TypeName(objHtmlElement)) = "HTMLDOCUMENT" Then
			Set colHtmlFrames = objHtmlElement.GetElementsByTagName("FRAME")
			
			If colHtmlFrames.Length > 0 Then
				Set objElementsCollection = objHtmlElement.GetElementsByTagName("FRAME")
			Else
				Set objElementsCollection = objHtmlElement.GetElementsByTagName("IFRAME")
			End If
		Else
			Set objElementsCollection = objHtmlElement.GetElementsByTagName("IFRAME")
		End If
	End If

	For i=0 To objElementsCollection.Length-1
		Do While True
			For k=0 To UBound(arrPropertyNames)
				If Internal_GetProperty(objElementsCollection(i), arrPropertyNames(k), varPropertyValue) Then
					If Not RegExpMatch(objProperties.Item(arrPropertyNames(k)), varPropertyValue, vbNullString) Then
						Exit Do
					End If
					
				Else
					Exit Do
				End If
			Next
			
			If intPropertyIndex <> 0 Then
				If intPropertyIndex = i+1 Then
					colElementsCollection.AddElement(GetElementFromFactory(objElementsCollection(i), strElementClass))
				End If
			Else
				colElementsCollection.AddElement(GetElementFromFactory(objElementsCollection(i), strElementClass))
			End If

			Exit Do
		Loop
	Next
End Function

Private Function GetElementFromFactory(ByVal objHtmlElement, ByVal strElementClass)
	strElementClass = Trim(LCase(strElementClass))
	
	Select Case strElementClass
		Case "link"
			Set oElementClass = New Link

		Case "table"
			Set oElementClass = New Table

		Case "text field"
			Set oElementClass = New TextField
			
		Case "check box"
			Set oElementClass = New Checkbox
			
		Case "radio button"
			Set oElementClass = New Radiobutton
			
		Case "list box"
			Set oElementClass = New Listbox
			
		Case "button"
			Set oElementClass = New Button
			
		'Case "cell"
		'	Set oElementClass = New Cell
		
		Case "file field"
			Set oElementClass = New FileField
		
		Case "frame"
			Set oElementClass = New Frame
		
		'Case "image area"
		'	Set oElementClass = New ImageArea
		
		'Case "object"
		'	Set oElementClass = New Object
		
		Case "document"
			Set oElementClass = New Document
		
		'Case "image"
		'	Set oElementClass = New Image
			
		Case Else
			Set oElementClass = New GenericElement
			
	End Select
	
	oElementClass.WrapElement(objHtmlElement)
			
	Set GetElementFromFactory = oElementClass
End Function

Private Function ElementClassToHtmlTag(strElementClass)
	strElementClass = Trim(LCase(strElementClass))
	
	Select Case strElementClass
		Case "cell"
			ElementClassToHtmlTag = "TD"
			
		Case "image area"
			ElementClassToHtmlTag = "IMAGEAREA"
			
		Case "object"
			ElementClassToHtmlTag = "OBJECT"
				
		Case "link"
			ElementClassToHtmlTag = "A"
		
		Case "table"
			ElementClassToHtmlTag = "TABLE"

		Case "text field", "check box", "radio button", "button", "file field"
			ElementClassToHtmlTag = "INPUT"
			
		Case "image"
			ElementClassToHtmlTag = "IMG"
			
		Case "list box"
			ElementClassToHtmlTag = "SELECT"
			
		Case Else
			ElementClassToHtmlTag = "*"
	
	End Select
End Function

Private Function Internal_GetProperty(ByVal objHtmlElement, ByVal strPropertyName, ByRef varPropertyValue)
	On Error Resume Next

	Dim varValue

	Internal_GetProperty = True
	strPropertyName = Trim(LCase(strPropertyName))

	Select Case strPropertyName
		Case "value"
			varValue = Trim(objHtmlElement.Value)
		
		Case "inner text", "text"
			varValue = Trim(objHtmlElement.InnerText)
		
		Case "html tag"
			varValue = objHtmlElement.TagName
		
		Case "type"
			varValue = objHtmlElement.Type
			
		Case "name"
			varValue = objHtmlElement.Name
			
		Case "class name"
			varValue = objHtmlElement.ClassName
			
		Case "html id"
			varValue = objHtmlElement.Id
		
		Case "unique id"
			varValue = objHtmlElement.UniqueId
			
		Case "default value"
			varValue = objHtmlElement.DefaultValue
				
		Case "max length"
			varValue = objHtmlElement.MaxLength
				
		Case "read only"
			varValue = CBool(objHtmlElement.ReadOnly)
			
		Case "alt"
			varValue = objHtmlElement.Alt
			
		Case "src"
			varValue = objHtmlElement.Src
			
		Case "title"
			varValue = objHtmlElement.Title
				
		Case "background color"
			varValue = objHtmlElement.CurrentStyle.BackgroundColor
				
		Case "visible"
			Dim blnVisible
			
			blnVisible = True
		
			Set objHtmlTemporaryElement = objHtmlElement
			
			Do				
				If objHtmlTemporaryElement.CurrentStyle.Display = "none" Then
					blnVisible = False

					Exit Do
				End If
			
				Set objHtmlTemporaryElement = objHtmlTemporaryElement.ParentNode
			Loop Until TypeName(objHtmlTemporaryElement) = "HTMLBody"
			
			varValue = blnVisible
				
		Case "color"
			varValue = objHtmlElement.CurrentStyle.Color
			
		Case "all items"
			Dim strItems
			Dim intItemsCount
			Dim i
			
			intItemsCount = objHtmlElement.Options.Length
		
			For i = 0 To intItemsCount - 1
				strItems = strItems & objHtmlElement.Options(i).Text & ";"
			Next
			
			strItems = Left(strItems, Len(strItems)-1)				
			varValue = strItems
				
		Case "disabled"
			varValue = CBool(objHtmlElement.Disabled)
		
		Case "multiple"
			varValue = CBool(objHtmlElement.Multiple)
			
		Case "items count"
			varValue = CInt(objHtmlElement.Length)

		Case "visible items"
			varValue = CInt(objHtmlElement.Size)
		
		Case "href", "url"
			If InStr(1, UCase(TypeName(objHtmlElement)), "FRAME") > 0 Then
				varValue = objHtmlElement.ContentWindow.Document.Url
			Else
				varValue = objHtmlElement.Href
			End If
			
		Case "checked"
			varValue = CBool(objHtmlElement.Checked)

		Case "default checked"
			varValue = CBool(objHtmlElement.DefaultChecked)
		
		Case "rows count"
			varValue = CInt(objHtmlElement.Rows.Length)

		Case "outer text"
			varValue = Trim(objHtmlElement.OuterText)
			
		Case "inner html"
			varValue = Trim(objHtmlElement.InnerHtml)
		
		Case "outer html"
			varValue = Trim(objHtmlElement.OuterHtml)
		
		Case "x"		
			varValue = CInt(objHtmlElement.OffsetLeft)
			
			Set objOffsetParent = objHtmlElement
			
			Do While True
				Set objOffsetParent = objOffsetParent.OffsetParent
				
				If objOffsetParent Is Nothing Then Exit Do
				
				varValue = varValue + CInt(objOffsetParent.OffsetLeft)
			Loop
		
		Case "y"
			varValue = CInt(objHtmlElement.OffsetTop)
			
			Set objOffsetParent = objHtmlElement
			
			Do While True
				Set objOffsetParent = objOffsetParent.OffsetParent
				
				If objOffsetParent Is Nothing Then Exit Do
				
				varValue = varValue + CInt(objOffsetParent.OffsetTop)
			Loop
		
		Case "file name"			
			strPathToImageFile = objHtmlElement.Src
			
			arrPathToImageFile = Split(strPathToImageFile, "/")
			
			If IsArray(arrPathToImageFile) Then
				varValue = arrPathToImageFile(UBound(arrPathToImageFile))
			Else
				varValue = strPathToImageFile
			End If

		Case "cols"
			strHtmlTagName = UCase(objHtmlElement.TagName)
			
			If strHtmlTagName = "TABLE" Then
				varValue = CInt(objHtmlElement.Rows(0).Cells.Length)
			ElseIf strHtmlTagName = "TEXTAREA" Then
				varValue = CInt(objHtmlElement.Cols)
			Else
				Err.Rise 10009, "Internal_GetProperty", "The html element doesn't support this property"
			End If
			
		Case "rows"
			strHtmlTagName = UCase(objHtmlElement.TagName)
			
			If strHtmlTagName = "TABLE" Then
				varValue = CInt(objHtmlElement.Rows.Length)
			ElseIf strHtmlTagName = "TEXTAREA" Then
				varValue = CInt(objHtmlElement.Rows)
			Else
				Err.Rise 10009, "Internal_GetProperty", "The html element doesn't support this property"
			End If
		
		Case "width"
			If strElementClass = "IMAGE" Then
				varValue = CInt(objHtmlElement.Width)
			Else
				varValue = CInt(objHtmlElement.OffsetWidth)
			End If
		
		Case "width in characters"
			varValue = Len(objHtmlElement.Value)
		
		Case "height"
			If strElementClass = "IMAGE" Then
				varValue = CInt(objHtmlElement.Height)
			Else
				varValue = CInt(objHtmlElement.OffsetHeight)
			End If
		
		Case "target"
			varValue = objHtmlElement.Target
		
		Case "cords"
			varValue = objHtmlElement.Coords
		
		Case "shape"
			varValue = objHtmlElement.Shape
		
		Case "selection", "selected item index"
			strItems = ""
			intItemsCount = objHtmlElement.Options.Length
		
			For i = 0 To intItemsCount - 1
				If objHtmlElement.Options(i).Selected = True Then
					If strPropertyName = "selection" Then
						strItems = strItems & Trim(objHtmlElement.Options(i).Text) & ";"
					Else
						strItems = i & ";"
					End If
				End If
			Next
			
			strItems = Left(strItems, Len(strItems)-1)
			varValue = strItems
		
		Case "selected items count"
			intItemsSelectedCount = 0
			intItemsCount = objHtmlElement.Options.Length
		
			For i = 0 To intItemsCount - 1
				If objHtmlElement.Options(i).Selected = True Then
					intItemsSelectedCount = intItemsSelectedCount + 1
				End If
			Next
			
			varValue = intItemsSelectedCount
		
		Case "rel"
			varValue = objHtmlElement.Rel
			
		Case "rev"
			varValue = objHtmlElement.Rev
			
		'Case "map name"
		'Case "kind"
		'Case "abs x"
		'Case "abs y"
		'Case "alias name"
		'Case "image type"
		'Case "select type"
		
		Case Else
			Err.Rise 10009, "Internal_GetProperty", "The html element doesn't support this property"
			
	End Select
	
	varPropertyValue = varValue
	
	If Err.Number <> 0 Then
		Internal_GetProperty = False
		
		Err.Clear
	End If
	
	On Error GoTo 0
End Function

Private Function RegExpMatch(ByVal strPattern, ByVal strText, ByVal arrMatches)
	RegExpMatch = False

	Set objRegExp = WScript.CreateObject("VBScript.RegExp")
	
	objRegExp.Pattern = strPattern
	objRegExp.IgnoreCase = True
	objRegExp.Global = True
	'oRegExp.Multiline = True

	If objRegExp.Test(strText) Then
		Set objMatches = objRegExp.Execute(strText)
		
		ReDim arrMatches(-1)
		
		For Each objMatch in objMatches
			ReDim Preserve arrMatches(UBound(arrMatches)+1)
			
			arrMatches(UBound(arrMatches)) = objMatch.Value
		Next
	   
		Set objMatches = Nothing
		
		RegExpMatch = True
	End If
	
	Set objRegExp = Nothing
End Function